tmem: Don't crash/hang/leak hypervisor when using shared pools within an guest.
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Wed, 26 Aug 2015 17:15:03 +0000 (13:15 -0400)
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Wed, 2 Sep 2015 12:47:59 +0000 (08:47 -0400)
commit7ec4b2f89e54d8bdfbeb5f4a4c2ec85d15819e8b
tree0ef05ed083537a267bb85a104ed6dac9441d4c90
parentafc13fe5e21d18c09e44f8ae6f7f4484e9f1de7f
tmem: Don't crash/hang/leak hypervisor when using shared pools within an guest.

This is a regression introduced by a36590e1b5040838af19d2ca712a516f07a6062b
"tmem: reorg the shared pool allocate path".

When we are using shared pools we have an global array
(on which we put the pool), and an array of pools per domain.
We also have an shared list of clients (guests) _except_
for the very first domain that created the shared pool.

To deal with multiple guests using an shared pool we have an
ref count and a linked list. Whenever an new user of
a the shared pool joins we increase the ref count and add to
the linked list. Whenever an user quits the shared pool
we decrement and remove from the linked list.

Unfortunately this ref counting and linked list never
worked properly. There are multiple issues:

 1) If we have one shared pool (and only one guest creating it)
    - we do not add it to the shared list of clients. Which
    means the logic in 'shared_pool_quit' never removed
    the pool from global_shared_pools. That meant when the pool
    was de-allocated - we still had an pointer to the pool
    which would be accessed by tmemc_list_client (xl tmem-list -a)
    and hit a NULL page!

 2). If we have two shared pools in a domain - it (shared_pool_quit)
     would remove the domain from the share_list linked list, decrements
     the refcount to zero - and remove the pool from the global shared pool.
     When done it would also clear the client->pools[] to NULL for itself.
     Which is good. However since there are two shared pools in the domain
     the next entry in the client->pools[] would have a stale pointer to
     the just de-allocated pool. Accessing it and trying to de-allocate it
     would lead to crashes or hypervisor hang - depending on the build.

Fun times!

To trigger this use
http://xenbits.xen.org/gitweb/?p=xentesttools/bootstrap.git;a=blob;f=root_image/drivers/tmem_test/tmem_test.c

This patch fixes it by making the very first domain that created
an shared pool to follow the same logic as every domain that is
joining a shared pool. That is increment the refcount and also
add itself to the shared list of domains using it.

We also remove an ASSERT that incorrectly assumed
that only one shared pool would exist for a domain.

And to mirror the reporting logic in shared_pool_join
we also add a printk to advertise inter-domain shared pool
joining.

Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Release-acked-by: Wei Liu <wei.liu2@citrix.com>
xen/common/tmem.c